Skip to content

Send DbType.Decimal and DbType.DateTime2 as their types - #382

Open
alaricd wants to merge 2 commits into
Giorgi:developfrom
pengdows:fix/decimal-dbtype
Open

alaricd wants to merge 2 commits into
Giorgi:developfrom
pengdows:fix/decimal-dbtype

Conversation

@alaricd

@alaricd alaricd commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

DbType.Decimal and DbType.DateTime2 have no entry in ClrToDuckDBConverter.ValueCreators. A parameter declared with either type falls through to NativeMethods.Value.DuckDBCreateVarchar(item.ToString()), so the value is sent as text in the current culture. Under fr-FR or de-DE, a declared decimal is sent as 1234,5:

Statement (DuckDB.NET 1.5.6.1, de-DE) DbType.Decimal, Value = 1234.5m
INSERT into a VARCHAR column stores 1234,5
INSERT into a DOUBLE column Conversion Error: Could not convert string '1234,5' to DOUBLE
SELECT ? returns the string 1234,5, not a decimal

A DECIMAL column is not affected, because the target type routes the value through (DuckDBType.Decimal, decimal value) first.

Today this mostly stays hidden because a decimal value infers DbType.Currency, which does have a converter. Once #369 lets an explicit DbType survive assigning Value, every caller that sets DbType.Decimal hits this path.

Changes

  • DbType.Decimal gets a converter: a decimal is sent as a DECIMAL, exactly like DbType.Currency. Any other value keeps the previous fallback, so DbType.Decimal with an int still works. A text value is sent whole, NUL characters included, through the same CreateVarchar path as other strings.
  • DbType.DateTime2 is sent like DbType.DateTime (a TIMESTAMP). Any other value keeps the previous fallback, through the same CreateVarchar path.
  • A decimal value now infers DbType.Decimal instead of DbType.Currency. This matches the ADO.NET inference table and DuckDB.NET's own GetSchema("DataTypes") (Support ADO.NET schema data types and metadata probing #364), which maps DECIMAL to System.Decimal. Binding does not change: both types send the same DECIMAL value, and DbType.Currency keeps working when set explicitly.

Tests

  • DecimalValueInfersDbTypeDecimal
  • ExplicitDecimalDbTypeIsSentAsADecimalInAnyCulture (Decimal and Currency, under fr-FR: SELECT ?, a VARCHAR column and a DOUBLE column)
  • ExplicitDecimalDbTypeWithAnIntegerValueIsStillSent
  • ExplicitDecimalDbTypeWithATextValueKeepsItsNulCharacters (fails with the fallback going straight to DuckDBCreateVarchar: length is 1, not 3)
  • ExplicitDateTime2DbTypeIsSentAsATimestampInAnyCulture (de-DE)
  • ExplicitDateTime2DbTypeWithATextValueIsStillSent

The six tests above pass in each of five repeated runs on the rebased branch.

Rebase and verification (this update)

  • Rebased onto develop at 881ef26 (97 commits ahead of the previous base). One conflict in ClrToDuckDBConverter.cs, with CreateVarchar from upstream kept and TimestampToDuckDBValue added beside it.
  • Commit ce3dc01 routes the new fallbacks through CreateVarchar (which upstream added for NUL-safe strings) and adds the NUL test.
  • DuckDB.NET.Data and DuckDB.NET.Test build with 0 warnings on net8.0 (/p:BuildType=Full, Release).
  • Full DuckDB.NET.Test suite, net8.0, including the connection stress tests: 3942 passed, 1 skipped in the runs that completed clean. In 3 of 7 full runs on this branch, one other test failed: DuckDBDataReaderMemoryTests.NextResultReleasesPreviousResult. It asserts that process memory growth stays under 100 MB over 20 runs. It fails in isolation on this branch (4 of 5 runs) and also fails on a clean develop checkout at 881ef26 (5 of 5 runs, growth 118 MB), so it is a pre-existing failure and not caused by this change. It is not fixed here.
  • Not verified on this rebase: the Release package build with native libraries for all platforms, and net10.0 test execution (the test project targets net8.0 only).

🤖 Generated with Claude Code

@coveralls

coveralls commented Oct 23, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 42224635644

Coverage decreased (-0.006%) to 93.631%

Details

  • Coverage decreased (-0.006%) from the base build.
  • Patch coverage: 7 of 7 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 4582
Covered Lines: 4335
Line Coverage: 94.61%
Relevant Branches: 3017
Covered Branches: 2780
Branch Coverage: 92.14%
Branches in Coverage %: Yes
Coverage Strength: 1055840.63 hits per line

💛 - Coveralls

alaricd and others added 2 commits November 6, 2026 05:19
Neither had a value converter, so a parameter declared with one was sent
as ToString() in the current culture: "1234,5" under fr-FR, stored as such
in a VARCHAR column and refused by a DOUBLE one. A decimal value now infers
DbType.Decimal, as the ADO.NET inference table and GetSchema("DataTypes")
say, instead of DbType.Currency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new converters fell back to DuckDBCreateVarchar(string), which stops at a
NUL character. Route the fallback through CreateVarchar, as the other string
values are, and test a text value with a NUL character.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

This branch is waiting to be deployed

1 waiting deployment
external — ce3dc011 Waiting Nov 6, 2026 by alaricd via Authorize #739
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants